home *** CD-ROM | disk | FTP | other *** search
- // VirtualDub - Video processing and capture application
- // Copyright (C) 1998-2001 Avery Lee
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 2 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- #include <string.h>
- #include <windows.h>
-
- #include "VBitmap.h"
- #include "Histogram.h"
- #include "Error.h"
-
- const char histo_log_table[]={
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,7,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 7,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
- 6,6,6,6,6,6,6,6,6,6,6,6,5,5,5,5,
- 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
- 5,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,
- 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
- 4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- };
-
- const RGBQUAD Histogram::fore_colors[]={
- { 0xff, 0x00, 0x00 },
- { 0x00, 0xff, 0x00 },
- { 0x00, 0x00, 0xff },
- { 0xff, 0xff, 0xff },
- };
-
- Histogram::Histogram(HDC hDC, int max_height) {
- struct {
- BITMAPINFO bmi;
- RGBQUAD bmiColor1;
- } bmp;
-
- hBitmapGraph = NULL;
- hDCGraph = NULL;
-
- bmp.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmp.bmi.bmiHeader.biWidth = 256;
- bmp.bmi.bmiHeader.biHeight = max_height;
- bmp.bmi.bmiHeader.biPlanes = 1;
- bmp.bmi.bmiHeader.biBitCount = 1;
- bmp.bmi.bmiHeader.biCompression = BI_RGB;
- bmp.bmi.bmiHeader.biSizeImage = max_height * 32;
- bmp.bmi.bmiHeader.biXPelsPerMeter = 80;
- bmp.bmi.bmiHeader.biYPelsPerMeter = 72;
- bmp.bmi.bmiHeader.biClrUsed = 2;
- bmp.bmi.bmiHeader.biClrImportant = 2;
- bmp.bmi.bmiColors[0].rgbBlue = 0;
- bmp.bmi.bmiColors[0].rgbGreen = 0;
- bmp.bmi.bmiColors[0].rgbRed = 0;
- bmp.bmiColor1.rgbBlue = 0;
- bmp.bmiColor1.rgbGreen = 0;
- bmp.bmiColor1.rgbRed = 0xff;
-
- if (!(hDCGraph = CreateCompatibleDC(hDC)))
- throw MyError("Histogram: Couldn't create display context");
-
- if (!(hBitmapGraph = CreateDIBSection(hDC, &bmp.bmi, DIB_RGB_COLORS, (LPVOID *)&lpGraphBits, NULL, 0)))
- throw MyError("Histogram: Couldn't allocate DIB section");
-
- SelectObject(hDCGraph, hBitmapGraph);
-
- this->max_height = max_height;
-
- SetMode(MODE_GRAY);
- }
-
- Histogram::~Histogram() {
- if (hBitmapGraph) DeleteObject(hBitmapGraph);
- if (hDCGraph) DeleteDC(hDCGraph);
- }
-
- void Histogram::Zero() {
- memset(histo, 0, sizeof histo);
- total_pixels = 0;
- }
-
- void Histogram::Process(const VBitmap *vbmp) {
- #if 0
- Pixel c, *src = (Pixel *)vbmp->data;
- long w, h;
-
- if (!vbmp->width || !vbmp->height) return;
-
- h = vbmp->height;
- do {
- w = vbmp->width;
- do {
- c = *src++;
- ++histo[(54*((c>>16)&255) + 183*((c>>8)&255) + 19*(c&255))>>8];
- } while(--w);
-
- src = (Pixel *)((char *)src + vbmp->modulo);
- } while(--h);
- #else
-
- if (histo_mode < MODE_GRAY)
- asm_histogram_color_run((char *)vbmp->data + histo_mode, vbmp->w, vbmp->h, vbmp->pitch, histo);
- else
- asm_histogram_gray_run(vbmp->data, vbmp->w, vbmp->h, vbmp->pitch, histo);
-
- #endif
-
- total_pixels += vbmp->w * vbmp->h;
- }
-
- void Histogram::Process24(const VBitmap *vbmp) {
- #if 0
- Pixel c, *src = (Pixel *)vbmp->data;
- long w, h;
-
- if (!vbmp->w || !vbmp->h) return;
-
- h = vbmp->h;
- do {
- w = vbmp->w;
- do {
- c = *src++;
- ++histo[(54*((c>>16)&255) + 183*((c>>8)&255) + 19*(c&255))>>8];
- } while(--w);
-
- src = (Pixel *)((char *)src + vbmp->modulo);
- } while(--h);
- #else
-
- if (histo_mode < MODE_GRAY)
- asm_histogram_color24_run((char *)vbmp->data + histo_mode, vbmp->w, vbmp->h, vbmp->pitch, histo);
- else
- asm_histogram_gray24_run(vbmp->data, vbmp->w, vbmp->h, vbmp->pitch, histo);
-
- #endif
-
- total_pixels += vbmp->w * vbmp->h;
- }
-
- void Histogram::Process16(const VBitmap *vbmp) {
- static const long pixmasks[3]={
- 0x001f,
- 0x03e0,
- 0x7c00,
- };
-
- if (histo_mode < MODE_GRAY)
- asm_histogram16_run(vbmp->data, vbmp->w, vbmp->h, vbmp->pitch, histo, pixmasks[histo_mode]);
- else
- asm_histogram16_run(vbmp->data, vbmp->w, vbmp->h, vbmp->pitch, histo, 0x7fff);
-
- total_pixels += vbmp->w * vbmp->h;
- }
-
- void Histogram::ComputeHeights(long *heights, long graph_height) {
- #if 0
- long h;
- double c = log(pow(2, 1.0/8.0));
-
- for(int i=0; i<256; i++) {
- if (!histo[i])
- heights[i] = 0;
- else {
- h = graph_height + log((double)histo[i]/total_pixels) / c;
-
- if (h<0)
- heights[i] = 1;
- else
- heights[i] = h;
- }
-
- // heights[i] = (histo[i]*graph_height + total_pixels - 1) / total_pixels;
- }
- #else
- long h;
- int s;
-
- for(int i=0; i<256; i++) {
- if (!histo[i])
- heights[i] = 0;
- else {
- if (histo[i] == total_pixels)
- heights[i] = graph_height;
- else {
- h = MulDiv(histo[i], 0x10000000L, total_pixels);
-
- if (!h)
- heights[i] = 1;
- else {
- s = -1;
-
- while(h<0x10000000) {
- h<<=1;
- ++s;
- }
-
- h = graph_height - 8*s - histo_log_table[(h>>20) & 255];
- if (h<1) h=1;
-
- heights[i] = h;
- }
- }
-
- }
-
- // heights[i] = (histo[i]*graph_height + total_pixels - 1) / total_pixels;
- }
- #endif
- }
-
- void Histogram::Draw(HDC hDC, LPRECT lpr) {
- long heights[256];
-
- #if 1
- int i,j;
-
- ComputeHeights(heights, lpr->bottom - lpr->top);
-
- GdiFlush();
-
- memset(lpGraphBits, 0, 32*(lpr->bottom - lpr->top));
-
- for(i=0; i<256; i++) {
- char *lp = lpGraphBits + (i>>3);
- char mask = 0x80 >> (i&7);
-
- j = heights[i];
- if(j) do {
- *lp |= mask;
- lp += 32;
- } while(--j);
- }
-
- BitBlt(hDC, lpr->left,lpr->top, 256, lpr->bottom-lpr->top, hDCGraph, 0, 0, SRCCOPY);
- #else
- long frac_accum, frac_inc;
- long width = lpr->right - lpr->left;
- long height = lpr->bottom - lpr->top;
- HPEN hPenOld, hPenPositive, hPenNegative;
- int i;
-
- frac_inc = width<256 ? 0xFFFFFF/(width-1) : (0x1000000+width/2)/width;
-
- ComputeHeights(heights, height);
-
- hPenPositive = CreatePen(PS_SOLID, 0, RGB(255,0,0));
- hPenNegative = CreatePen(PS_SOLID, 0, RGB(0,0,0));
-
- if (hPenPositive && hPenNegative) {
- hPenOld = SelectObject(hDC, hPenNegative);
-
- frac_accum = 0;
-
- for(i=0; i<width; i++) {
- if (heights[frac_accum>>16]<height) {
- MoveToEx(hDC, lpr->left+i, lpr->top, NULL);
- LineTo(hDC, lpr->left+i, lpr->top+(height-heights[frac_accum>>16]));
- }
-
- frac_accum += frac_inc;
- }
-
- SelectObject(hDC, hPenPositive);
-
- frac_accum = 0;
-
- for(i=0; i<width; i++) {
- if (heights[frac_accum>>16]) {
- MoveToEx(hDC, lpr->left+i, lpr->top+(height-heights[frac_accum>>16]), NULL);
- LineTo(hDC, lpr->left+i, lpr->bottom);
- }
-
- frac_accum += frac_inc;
- }
-
- SelectObject(hDC, hPenOld);
- }
-
- if (hPenPositive) DeleteObject(hPenPositive);
- if (hPenNegative) DeleteObject(hPenNegative);
- #endif
- }
-
- void Histogram::SetMode(int new_mode) {
- if (new_mode == MODE_NEXT) {
- if (++histo_mode >= NUM_MODES) histo_mode = 0;
- } else
- histo_mode = new_mode;
-
- SetDIBColorTable(hDCGraph, 1, 1, &fore_colors[histo_mode]);
-
- }
-
- int Histogram::GetMode() {
- return histo_mode;
- }
-